Public
Edited
Oct 18, 2023
Paused
8 forks
5 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
d3 = require('d3@7')
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// extract the 10 most populous countries in 2005
listData = gapminder
.filter(d => d.year === 2005)
.sort((a, b) => b.pop - a.pop)
.slice(0, 10)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// Run this cell to recolor just the first item in the list above.
// If you are curious rhe randomColor() function was imported as a utility at the end of this document.
d3.select('li.country').style('color', randomColor()), null
Insert cell
// Run this cell to recolor ALL items in the list above
d3.selectAll('li.country').style('color', randomColor()), null
Insert cell
Insert cell
{
const ol = d3.create('ol');
ol.selectAll('li') // select all list elements (orange circle below)
.data(listData) // bind all our data values (blue circle below)
return ol.node();
}
Insert cell
Insert cell
selection = {
const ol = d3.create('ol');
return ol.selectAll('li').data(listData);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const ol = d3.create('ol');

ol.selectAll('li') // select all list elements (orange circle above)
.data(listData) // bind all our data values (blue circle above)
.join('li') // merge the 'enter' and 'update' sets, create 'li' elements as needed
.text(d => `${d.country}: ${d.pop}`) // For data-bound selections, transformation operators can be
// functions that receive a data value as an input argument.
return ol.node();
}
Insert cell
Insert cell
{
const ol = d3.create('ol');
ol.selectAll('li') // select all list elements (orange circle above)
.data(listData) // bind all our data values (blue circle above)
.join(
enter => enter.append('li'), // append an li element for each entering item
update => update, // do nothing with items that match an existing element
exit => exit.remove() // remove li elements whose backing data is now gone
)
.text(d => `${d.country}: ${d.pop}`)
return ol.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
{
const ol = d3.select('ol#enter-update-exit');

// use a new dataset, manipulable with the variables defined below
const newData = gapminder
.filter(d => d.year === year)
.sort((a, b) => b.pop - a.pop)
.slice(0, n);
ol.selectAll('li') // select all list elements (orange circle above)
.data(newData) // bind all our data values (blue circle above)
.join(
enter => enter.append('li'), // hint: add code here
update => update, // hint: add code here
exit => exit.remove()
)
.text(d => `${d.country}: ${d.pop}`);
}
Insert cell
Insert cell
year = 2005
Insert cell
n = 10
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const container = d3.create('div');
// Add code here to generate the bar chart within the container.
// Use 'div' elements for each bar.
// Make sure you set some text to each div in order to make sure the bars appear.
// The 'barData' variable holds the data to visualize as a set
// of objects with 'key' and 'value' properties.
return container.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
md`The current page \`width\` variable = ${width} px.` // Observable's built-in width property!
Insert cell
xscale = d3.scaleLinear()
.domain([0, d3.max(barData, d => d.value)])
.range([0, width])
Insert cell
Insert cell
xscale(49)
Insert cell
Insert cell
{
const container = d3.create('div');

container.selectAll('div')
.data(barData)
.join('div')
.style('background', 'steelblue')
.style('border', '1px solid white')
.style('font-size', 'small')
.style('color', 'white')
.style('text-align', 'right')
.style('padding', '3px')
.style('width', d => `${xscale(d.value)}px`) // <-- Use xscale instead of a magic number
.text(d => d.value);
return container.node();
}
Insert cell
Insert cell
color = d3.scaleOrdinal(d3.schemeTableau10).domain(barData.map(d => d.key));
// Default color schemes are here: https://github.com/d3/d3-scale-chromatic#categorical
// Try another one!
Insert cell
{
const container = d3.create('div');

container.selectAll('div')
.data(barData)
.join('div')
.style('background', d => color(d.key))
.style('border', '1px solid white')
.style('font-size', 'small')
.style('color', 'white')
.style('text-align', 'right')
.style('padding', '3px')
.style('width', d => `${xscale(d.value)}px`)
.text(d => d.value);

return container.node();
}
Insert cell
Insert cell
Insert cell
{
const barHeight = 25;
const height = barData.length * barHeight;

// create svg element, specify total width and height
const container = d3.create('svg')
.attr('width', width)
.attr('height', height);

// add SVG 'rect' elements for bars
container.selectAll('rect')
.data(barData)
.join('rect')
.attr('x', 0)
.attr('y', (d, i) => i * barHeight)
.attr('width', d => xscale(d.value))
.attr('height', barHeight)
.style('fill', d => color(d.key))
.style('stroke', 'white');

// add SVG 'text' elements for labels
container.selectAll('text')
.data(barData)
.join('text')
.attr('x', d => xscale(d.value))
.attr('y', (d, i) => i * barHeight)
.attr('dx', -20)
.attr('dy', '1.25em')
.attr('fill', 'white')
.style('font-size', 'small')
.text(d => d.value);

// return SVG DOM element
return container.node();
}
Insert cell
Insert cell
Insert cell
height = 150
Insert cell
yscale = d3.scaleBand()
.domain(barData.map(d => d.key))
.range([height, 0]) // Try flipping this to [0, height] and see the effect on the bars below.
Insert cell
Insert cell
{
const container = d3.create('svg')
.attr('width', width)
.attr('height', height);

container.selectAll('rect')
.data(barData)
.join('rect')
.attr('x', 0)
.attr('y', d => yscale(d.key)) // <-- Use yscale instead of manually positioning bars
.attr('width', d => xscale(d.value))
.attr('height', yscale.bandwidth()) // <-- Band scales split a pixel range into equal-sized bands
.style('fill', d => color(d.key))
.style('stroke', 'white');

container.selectAll('text')
.data(barData)
.join('text')
.attr('x', d => xscale(d.value))
.attr('y', d => yscale(d.key)) // <-- Use yscale instead of manually positioning labels
.attr('dx', -20)
.attr('dy', '1.2em')
.attr('fill', 'white')
.style('font-size', 'small')
.text(d => d.value);

return container.node();
}
Insert cell
Insert cell
Insert cell
{
const width = 400;
const height = 200;

const container = d3.create('svg')
.attr('width', width)
.attr('height', height);

// Redefine the x scale here.
const xscale = /* add code here */;

// Redefine the y scale here.
const yscale = /* add code here */;

container.selectAll('rect')
.data(barData)
.join('rect')
.attr('x', d => /* add code here */)
.attr('y', d => /* add code here */)
.attr('width', d => /* add code here */)
.attr('height', d => /* add code here */)
.style('fill', d => color(d.key))
.style('stroke', 'white');

container.selectAll('text')
.data(barData)
.join('text')
.attr('x', d => /* add code here */)
.attr('y', d => /* add code here */)
.attr('dx', /* add code here */)
.attr('dy', '1em')
.attr('fill', 'white')
.style('font-size', 'small')
.style('text-anchor', 'middle')
.text(d => d.value);
return container.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
{
const container = d3.create('svg')
.attr('width', width)
.attr('height', height);

const g = container.selectAll('g')
.data(barData)
.enter() // <-- We use "enter" (not "join") so we can later append <rect> and <text> only for new data.
.append('g')
.attr('transform', d => `translate(0, ${yscale(d.key)})`);

g.append('rect')
// We no longer need to bind data to <rect>, or specify y positions.
.attr('width', d => xscale(d.value))
.attr('height', yscale.bandwidth())
.style('fill', d => color(d.key))
.style('stroke', 'white');

g.append('text')
// We no longer need to bind data to <text>, or specify y positions.
.attr('x', d => xscale(d.value))
.attr('dx', -20)
.attr('dy', '1.2em')
.attr('fill', 'white')
.style('font-size', 'small')
.text(d => d.value);
return container.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
margin = ({top: 10, right: 10, bottom: 20, left: 20})
Insert cell
Insert cell
xMargin = xscale.copy().range([margin.left, width - margin.right])
Insert cell
// Remember (0, 0) is the top-left hand corner
yMargin = yscale.copy().range([height - margin.bottom, margin.top])
Insert cell
Insert cell
{
const container = d3.create('svg')
.attr('width', width)
.attr('height', height)
.style('border', '1px dotted #999'); // <-- A dotted border helps us see the added margin

const g = container.selectAll('g')
.data(barData)
.enter()
.append('g')
.attr('transform', d => `translate(${margin.left}, ${yMargin(d.key)})`);

g.append('rect')
.attr('width', d => xMargin(d.value) - xMargin(0)) // <-- We must subtract our left offset.
.attr('height', yMargin.bandwidth())
.style('fill', d => color(d.key))
.style('stroke', 'white');

g.append('text')
.attr('x', d => xMargin(d.value) - xMargin(0)) // <-- We must subtract our left offset.
.attr('dx', -20)
.attr('dy', '1em')
.attr('fill', 'white')
.style('font-size', 'small')
.text(d => d.value);

return container.node();
}
Insert cell
Insert cell
{
const container = d3.create('svg')
.attr('width', width)
.attr('height', height)
.style('border', '1px dotted #999');

container.append('g')
.attr('transform', `translate(0, ${height - margin.bottom})`)
.call(d3.axisBottom(xMargin));

container.append('g')
.attr('transform', `translate(${margin.left}, 0)`)
.call(d3.axisLeft(yMargin));

return container.node();
}
Insert cell
Insert cell
{
const container = d3.create('svg')
.attr('width', width)
.attr('height', height);

const g = container.selectAll('g')
.data(barData)
.enter()
.append('g')
.attr('transform', d => `translate(${margin.left}, ${yMargin(d.key)})`);

g.append('rect')
.attr('width', d => xMargin(d.value) - xMargin(0))
.attr('height', yMargin.bandwidth())
.style('fill', d => color(d.key))
.style('stroke', 'white');

g.append('text')
.attr('x', d => xMargin(d.value) - xMargin(0))
.attr('dx', -20)
.attr('dy', '1em')
.attr('fill', 'white')
.style('font-size', 'small')
.text(d => d.value);

container.append('g')
.attr('transform', `translate(0, ${height - margin.bottom})`)
.call(d3.axisBottom(xMargin));

container.append('g')
.attr('transform', `translate(${margin.left}, 0)`)
.call(d3.axisLeft(yMargin));

return container.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more